Modern Python part 1: pyenvとpoetryでプロジェクトを初期化
著者:Faouzi BRAZA Jun 9, 2021
はじめに
プログラミング言語の学習では、基本的には構文やコードのスタイル、基本的な概念を理解することに重点が置かれます。時間が経てば、その言語に十分に慣れ、新しいエキサイティングな問題を解決するプログラムを書き始めることができます。
しかし、このステップに進むためには、適切な環境をいかにして構築するかという、過小評価されがちな側面があります。適切なソフトウェアエンジニアリングのプラクティスを実施し、生産性を向上させ、コラボレーションを促進する環境です。Adaltasでは、いくつかのオープンソースプロジェクトを管理しており、多くの貢献を歓迎しています。それらは主にNode.jsプラットフォームを対象としています。この経験に基づいて、私たちは、Node.jsで書かれた大規模プロジェクトを管理するための共通のプラクティスをすでに確立しています。
また、データコンサルタントとしての日常業務では、Pythonもよく使用しています。Pythonのパッケージ化やツール化は煩雑で難しいと言われています。この点については、ここ数年でいくつかのオープンソースプロジェクトが登場し、作業中のプロジェクトに沿ってPythonパッケージの管理を容易にすることを目的としています。ここでは、そのうちの2つのプロジェクトの使い方を見てみましょう。異なるPythonのバージョンを管理・インストールするPyenvと、パッケージと仮想環境を管理するPoetryです。これらを組み合わせることで、あるいは個別に使用することで、生産性の高い環境を構築することができます。
この記事は、私たちのベストプラクティスを共有する3つのシリーズの最初のものです。
日本語訳: Modern Python part 1: pyenvとpoetryでプロジェクトを初期化
前提条件
pyenvのインストール
pyenvをインストールするには、いくつかのOS固有の依存関係が必要です。これらは pyenv がソースからビルドして Python をインストールするために必要です。Ubuntu/Debianの場合、以下のパッケージがインストールされていることを確認してください。
code: bash
$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \
libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
お使いのOSに必要な依存関係については、こちらのドキュメントを参照してください。依存関係パッケージがインストールされたら、次にpyenvをインストールします。これには、プロセスを自動化するpyenv-installerを使うことをお勧めします。 code: bash
この後は、好きなバージョンのPythonをあなたのシステムにインストールすることができます。以下のコマンドで、利用可能なPythonのすべてのバージョンとフレーバーを確認できます。
code: bash
$ pyenv install --list
ここでは、古典的なCPythonのバージョン3.7.10 , 3.8.7 , 3.9.2をインストールする予定です。
code: bash
$ pyenv install 3.7.10
Downloading Python-3.7.10.tar.xz...
Installing Python-3.7.10...
Installed Python-3.7.10 to /home/fbraza/.pyenv/versions/3.7.10
次のコマンドでインストールされているPythonのバージョンを確認することができます。
code: bash
$ pyenv versions
* system
3.7.10
3.8.7
3.9.2
pyenv は、最近インストールされた Python のバージョンと、あなたのシステムにデフォルトでインストールされたバージョンを識別していることがわかります。この例で、system の前にある * は、現在使用されているグローバルバージョンがシステムバージョンであることを意味しています。 pyenv は Python のバージョンをグローバルとローカルという異なるレベルで管理することができます。ここでは、グローバルバージョンとしてバージョン3.7.10を設定することにしましょう。
code: bash
$ pyenv global 3.7.10
もう一度、インストールされているPythonのバージョンを確認してみましょう。
code: bash
$ pyenv versions
system
* 3.7.10 (set by /home/<username>/.pyenv/version)
3.8.7
3.9.2
pyenv が 3.7.10 をPythonのグローバルバージョンとして設定しているのがわかります。これは、システムバージョンの使用を必要とする操作を変更するものではありません。括弧にあるパスは、必要なPythonのバージョンを示すパスに対応しています。これはどのように機能するのでしょうか?簡単に言うと、pyenvはPATHに注入された実行ファイルを使ってPythonコマンドをキャプチャします。そして、使用する必要のあるPythonのバージョンを判断して、正しいPythonのインストールにコマンドを渡します。pyenvが提供する機能と可能性をよりよく理解するために、完全なドキュメント を読むことをお勧めします。 ここでは、混乱しないでください。グローバルバージョンを変更しても、システムバージョンには影響しません。システムバージョンは、あなたのOSが特定のタスクを実行したり、特定のPythonバージョンに依存するバックグラウンドプロセスを実行するために使用するバージョンに対応します。システムバージョンを別のものに変更しないでください。そうしないと、あなたのOSでいくつかの問題に直面するかもしれません。このバージョンは通常、OSと一緒に更新されます。グローバルバージョンは、Pythonコマンドやプログラムをグローバルに実行するために、pyenvが使用するバージョンです。
poetry のインストール
Poetry は、Python の依存関係やパッケージを効率的に管理することができます。poetry は setup.py や pipenv と同様の役割を果たしますが、より高い柔軟性と機能性を備えています。プロジェクトが依存するライブラリを pyproject.toml ファイルで宣言することができます。 poetry は必要に応じてそれらをインストールまたはアップデートします。さらにこのツールは、作業中のプロジェクトを隔離された環境にカプセル化することができます。最後に、poetryを使って、自分のパッケージをPypiで直接公開することもできます。
最後の前提条件として、以下のコマンドを実行してpoetryをインストールします。
code: bash
プロジェクトの作成
ここでは、pyenvとpoetryを使ってプロジェクトを作成し、Python環境の中で孤立させる方法を見ていきます。
PyenvによるPythonのバージョン設定
まず、my_awesome_project というディレクトリを作り、その中に移動しましょう。
code: bash
$ mkdir my_awesome_project && cd $_
ディレクトリの中に入ったら、使用するPythonのローカルバージョンを設定します(ここではPython 3.8.7を使用します)。
これにより、pyenv で定義されたローカルバージョンの Python を使用するよう poetry に指示されます。
code: bash
$ pyenv local 3.8.7
これにより、プロジェクト内に .python-version ファイルが作成されます。このファイルは pyenv によって読み込まれ、定義されたローカルな Python バージョンを設定するように促されます。その結果、この時点までに作成されたすべてのディレクトリやファイルは、グローバルなものではなく、ローカルなPythonバージョンに依存することになります。
poetryでプロジェクトを作成する
Poetry は、Python プロジェクトと依存関係を作成、設定、更新するための堅牢な CLI を提供します。Pythonプロジェクトを作成するには、以下のコマンドを使用します。
code: bash
$ poetry new <project_name>
このコマンドは、デフォルトのプロジェクト・スキャフォールドを生成します。新しいプロジェクトの内容は以下の通りです。
code: bash
.
├──
│ └── __init__.py
├── pyproject.toml
├── README.rst
└── tests
├── __init__.py
└── test_summarize_dataframe.py
pyproject.toml に注目してください。ここでは、プロジェクトのメタデータ、依存関係、スクリプトなどのすべてを定義します。Node.jsに慣れている方は、pyproject.toml は Node.js の package.json に相当するものと考えてください。
code: pyproject.toml
name = "your_project_name"
version = "0.1.0"
description = ""
python = "^3.8"
pytest = "^5.2"
build-backend = "poetry.core.masonry.api"
defaultpyproject.tomlファイルには、いくつかのエントリがあります。
[tool.poetry]という項目があります。このセクションには、パッケージに関するメタデータが含まれています。ここには、パッケージ名、短い説明文、作者の詳細、プロジェクトのバージョンなどを書くことができます。ここでの詳細はすべて任意ですが、パッケージをPypiで公開することになった場合には必須となります。
[tool.poetry.dependencies]: このセクションには、私たちのパッケージに必要なすべての依存関係が含まれています。これらのパッケージの具体的なバージョン番号を指定することもできますし(packageX = "1.0.0")、シンボルを使うこともできます。プロジェクトで使用したいPythonのバージョンもここで定義します。ここでは、python = "^3.8 "で、アプリを実行するのに必要な最小バージョンを指定しています。ここではPython 3.8とし、これはpyenvで定義されたローカルバージョンのバージョンに基づいています。
[tool.poetry.dev-dependencies]: このセクションには、このプロジェクトの作業や反復に必要なパッケージである、すべての開発者用の依存関係が含まれています。とはいえ、これらの依存関係はアプリの実行には必要ないので、パッケージのビルド時にはダウンロードされません。
[build-system] を参照してください。poetryのバージョンを更新していない限り、このセクションには触れないでください。
pyproject.tomlファイルで利用可能なエントリの全リストは、こちらを参照してください。 仮想環境のインストールと起動
ここでは2つのアプローチがあります。必要な依存関係をすべて事前に知っていて、それに合わせて.tomlファイルを直接変更するか、必要に応じて後から追加することにするかです。今回の例では、コードを書きながら徐々に依存関係を追加していくことにします。そのため、プロジェクトを初期化し、仮想環境を作成する必要があります。これを行うには、次のコマンドを実行します。
code: bash
$ poetry install
Creating virtualenv summarize-dataframe-SO-g_7pj-py3.8 in ~/.cache/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies... (6.4s)
Writing lock file
Package operations: 8 installs, 0 updates, 0 removals
• Installing pyparsing (2.4.7)
• Installing attrs (20.3.0)
• Installing more-itertools (8.7.0)
• Installing packaging (20.9)
• Installing pluggy (0.13.1)
• Installing py (1.10.0)
• Installing wcwidth (0.2.5)
• Installing pytest (5.4.3)
Installing the current project: summarize_dataframe (0.1.0)
まず最初に、仮想環境が作成され、プロジェクトの外に保存されます。これは、condaを使っているときと少し似ています。実際には、(virtualenvのように)依存ライブラリを含むフォルダを作成する代わりに、poetryはグローバルシステムパス(デフォルトでは.cache/)に環境を作成します。この関心事の分離により、依存関係にあるソースコードからプロジェクトを遠ざけることができます。
仮想環境は、プロジェクトの中にも、他のディレクトリにも作ることができます。そのためには、poetryの設定を編集する必要があります。詳しくはこちらのドキュメントをご覧ください。
次に、poetry は pyproject.toml を読み、このファイルで指定されたすべての依存関係をインストールします。定義されていない場合、poetryはパッケージの最終バージョンをダウンロードします。操作の最後には、poetry.lock ファイルが作成されます。このファイルには、すべてのパッケージとその正確なバージョンが含まれています。poetry.lockファイルがすでに存在している場合、そこに定義されているバージョン番号がpyproject.toml で定義されているものよりも優先されることに注意してください。最後に、poetry.lock ファイルをプロジェクトのリポジトリにコミットして、プロジェクトに参加しているすべての共同作業者が同じバージョンの依存関係を使用できるようにします。
それでは、先ほど作成した環境を次のコマンドで起動してみましょう。
code: bash
peotry shell
Spawning shell within ~/.cache/pypoetry/virtualenvs/summarize-dataframe-SO-g_7pj-py3.8
. ~/.cache/pypoetry/virtualenvs/summarize-dataframe-SO-g_7pj-py3.8/bin/activate
このコマンドは、親シェルを継承する子プロセスを作成しますが、その環境を変更することはありません。このプロセスは、あなたがプロジェクト環境に対して行うあらゆる変更をカプセル化し、制限します。
git リポジトリの作成
最後のステップでは、git リポジトリを作成し、README.md と .gitignore ファイルを追加して、すべてをリモートリポジトリにプッシュしたいと思います。
code: bash
$ git init
$ echo ".*\n!.gitignore" > .gitignore
$ echo "# Summarize dataframe" > README.md
$ git add .
$ git commit -m "build: first commit. Environment built"
$ git push -u origin master
まとめ
ここでは、pyenvを使ってマシンに異なるバージョンのPythonをインストールし、管理する方法を見てきました。pyenv local を利用して、プロジェクトに特定の Python バージョンを設定し、poetry を使用して仮想環境を作成する方法を示しました。poetryの使用は、シンプルで広くプロジェクトの足場を提案することで、作成のプロセスを実にスムーズにします。さらに、PEP 518で定義されている最小のビルドシステム要件も含まれています。
次回の記事では、プロジェクトをより深く掘り下げてみたいと思います。いくつかのコードをそれぞれのユニットテストとともに書き、期待される依存関係を追加してテストを実行するために poetry をどのように使用するかを見ていきます。最後に、もう少し踏み込んで、必要な依存関係をすべて poetry でインストールし、Python プロジェクトを使用しているときに git コミットで良い習慣を実行できるようにしたいと思います。
チートシート
pyenv
利用可能でインストール可能なすべてのPythonのバージョンを取得
code: bash
$ pyenv install --list
グローバルのPythonバージョンを設定する
code: bash
$ pyenv global <version_id>
ローカルのPythonバージョンを設定する
code: bash
$ pyenv local <version_id>
poetry
プロジェクトの作成
code: bash
$ poetry new <project_name>
仮想環境を作成してコアの依存パッケージをインストール
code: bash
$ poetry install
仮想環境を有効化
code: bash
$ poetry shell